#!/bin/sh
# a2webd (version 0.6) startup script for a2web.cgi
# Copyright (C) by Alex Bilinsky (@ß№®M!$) AbNoRMiS
# Licensed under GNU General Public License ver.3.0
# Feedback: <alex dot bilinsky at gmail dot com>
# Location: http://code.google.com/p/a2webd/
#
# Usage as daemon: a2webd [start|status|reload|restart|stop]
#
# Usage as browser starter: a2web [browser]
# Opens a2web.cgi in web browser
##
# Example: a2web google-chrome
##
# Options:
#   browser    run the specified browser
#
# get option from config file
# usage: get_option {option} {config_file}
get_option() { sed "/^$1/!d;s/^.*=//;s/^ //" $2; }
# start web browser
# usage: gui [browser]
gui() {
    daemon=`readlink $0`
#    $daemon status &>/dev/null
#    if [ $? -ne 0 ]; then
#	[ -d $RUN ] && $daemon restart &>/dev/null || $daemon start &>/dev/null
#    fi
    if $daemon status; then
	uri="$(get_option uri $A2WEBD_CONF)"
	uri="${uri#http://}"
	uri="http://${uri##*@}"
	xbrowsers="xdg-open
	    firefox icecat iceweasel seamonkey minefield namoroka conkeror
	    google-chrome chromium-browser iron opera opera-11 epiphany galeon
	    midori konqueror links links2 xlinks2 netsurf-gtk netsurf-fb
	    dillo chimera2 surf arora rekonq xxxterm"
	clibrowsers="links links2 elinks w3m lynx lynx.cur"
	# select x or cli browsers
	if [ "${x=`pgrep X`}" ] && [ "$DISPLAY" ] && [ "$TERM" == "linux" ]; then
	    browsers="$xbrowsers $clibrowsers"
	elif [ "$x" ] && [ "$DISPLAY" ]; then
	    browsers="$clibrowsers $xbrowsers"
	else
	    browsers="$clibrowsers"
	fi
	# start x or cli browser
	for item in $1 $browsers; do
	    [ "$1" ] && [ "$item" != "$1" ] && ERROR="or invalid name" && break
	    browser=`which $item`
	    if [ "$browser" ]; then
		if [ "$x" ] && [ "$DISPLAY" ] && [ "$TERM" == "linux" ]; then
		    if echo "$clibrowsers" | grep -qw $item && ! echo "$xbrowsers" | grep -qw $item; then
			xterm -T a2web -e "$browser $uri" && return $? || continue
		    else
			$browser $uri && return $? || continue
		    fi
		elif  [ "$x" ] && [ "$DISPLAY" ]; then
		    $browser $uri && return $? || continue
		else
		    if echo "$xbrowsers" | grep -qw $item && ! echo "$clibrowsers" | grep -qw $item; then
			echo "$item cannot run on command line" && return 1
		    else
			$browser $uri && return $? || continue
		    fi
		fi
	    fi
	done
	[ "$1" ] && echo -n "$1" || echo -n "Web"
	echo -e " browser not found $ERROR\n\n$(help starter)" && return 1
    fi
}
# print help
# usage: help {starter|daemon}
help() { sed "/$1:/,/^#$/!d;s/#[# ]//g;s/#//g;s/ as.*:/:/" $0; }
# set variables
THIS=${0##*/}
A2WEB=`find /usr -name a2web.cgi`
PREFIX=${A2WEB%%/share*}
[ "$PREFIX" == "/usr" ] && ETC=/etc || ETC=$PREFIX/etc
A2WEBD_CONF=$ETC/a2webd.conf
RUN=/var/run/$THIS
A2PID=$RUN/aria2.pid
# run a2web
if [ "$THIS" == "a2web" ]; then
    for item; do
	case $item in
	    -h|--help) help starter; exit ;;
	    *) browser=$item ;;
	esac
    done
    gui $browser
    exit $?
fi
# check root privileges for a2webd
[ `id -u` -ne 0 ] && [ "$1" != "status" ] && echo "$THIS must run with root privileges" && exit 1
# set option to config file
# usage: get_option {option} {delimiter} {value} {config_file}
set_option() { [ "$(get_option "$1" "$4")" ] && sed -i "/^$1/c\\$1$2$3" $4 || echo "$1$2$3" >> $4; }
# parse uri string
# usage: parse_uri {component} {uri}
parse_uri() {
    server_port=${2#*//}
    server_port=${server_port%%/*}
    user_password=`expr "$server_port" : "\(.*\)@"`
    server_port=${server_port##*@}
    case $1 in
	user) echo "${user_password%%:*}" ;;
	password) expr  "$user_password" : ".*:\(.*\)" ;;
	server) echo "${server_port%:*}" ;;
	port) expr  "$server_port" : ".*:\([0-9]*\)" ;;
	path) echo "${2#$user_password*$server_port}" ;;
    esac
}
# validate path or uri string
# usage: validate {path|uri} {string} [target]
validate() {
    # validate path string
    # usage: validate_path {string} [target]
    validate_path() {
	value=`expr "$1" : "\(\([/].*\)*$2\)$"`
	[ "$value" ] && return 0 || return 1
    }
    case $1 in
	path) validate_path "$2" "$3"; return $? ;;
	uri) [ "$(parse_uri server "$2")" ] && validate_path "$(parse_uri path "$2")" "$3"; return $? ;;
    esac
}
# get user
user() {
    for item in `last | sed '1!G;h;$!d' | sed '/root/d;/wtmp/d' | awk '{ print $1 }'`; do
	uid=`id -u $item` &>/dev/null && [ $uid -ge 1000 ] && [ $uid -lt 10000 ] && [ -d `eval echo ~$item` ] && echo $item && break #`egrep "^$item" /etc/passwd | cut -f6 -d:`
    done
}
# start
start() {
    # get error if a2webd already running
    if [ -d $RUN ]; then
	ERROR="a2web is already running"
    else
	# get error if not found installed a2web
	if [ -x $A2WEB ]; then
	    # get error if another aria2 instance running
	    if [ "$(pgrep aria2c)" ]; then
		ERROR="aria2 is already running"
	    else
		# set paths to config files
		USER=`user`
		HTTPD_CONF=$ETC/httpd.conf
		ARIA2_CONF=/home/$USER/.aria2/aria2.conf
		# create a2webd.conf if not exist
		if [ ! -f $A2WEBD_CONF ]; then
		    echo -e "# a2web.conf\n\n# Path to a2web.cgi in CGI directory of HTTP server\n# path = /path/to/cgi/dir/a2web.cgi\npath = $A2WEB\n" > $A2WEBD_CONF
		    echo -e "# uri = [http://][user[:password]@]server[:port]/path-to/a2web.cgi\nuri = http://localhost:8080/cgi-bin/a2web.cgi" >> $A2WEBD_CONF
		fi
		# read options from a2webd.conf
		A2WEB_PATH="$(get_option path $A2WEBD_CONF)"
		A2WEB_URI="$(get_option uri $A2WEBD_CONF)"
		# set path to a2web.conf
		A2WEB_CONF="${A2WEB_PATH%.*}.conf"
		# get error if wrong options
		if ! validate path "$A2WEB_PATH" a2web.cgi; then
		    ERROR="incorrect path in $A2WEBD_CONF"
		elif ! validate uri "$A2WEB_URI" a2web.cgi; then
		    ERROR="incorrect uri in $A2WEBD_CONF"
		else
		    # parse uri
		    HTTP_PASSWD="$(parse_uri password "$A2WEB_URI")"
		    HTTP_USER=`parse_uri user "$A2WEB_URI"`
		    HTTP_SERVER="$(parse_uri server "$A2WEB_URI")"
		    HTTP_PORT=`parse_uri port "$A2WEB_URI"`
		    HTTP_PATH="$(parse_uri path "$A2WEB_URI")"
		    # read options from aria2.conf if exist
		    if [ -f $ARIA2_CONF ]; then
			RPC_PORT=`get_option rpc-listen-port $ARIA2_CONF`
			RPC_USER=`get_option rpc-user $ARIA2_CONF`
			RPC_PASSWD="$(get_option rpc-passwd $ARIA2_CONF)"
		    fi
		    # set default ports if unset
		    [ "$RPC_PORT" ] || RPC_PORT=6800
		    [ "$HTTP_PORT" ] || HTTP_PORT=80
		    # check a2web.conf existence
		    if [ -f $A2WEB_CONF ]; then
			# set options from aria2.conf to a2web.conf if not specified
			[ "$RPC_PORT" ] && [ -z "$(get_option server $A2WEB_CONF)" ] && set_option server " = " "http://localhost:$RPC_PORT/rpc" $A2WEB_CONF
			[ "$RPC_USER" ] && [ -z "$(get_option user $A2WEB_CONF)" ] && set_option user " = " "$RPC_USER" $A2WEB_CONF
			[ "$RPC_PASSWD" ] && [ -z "$(get_option password $A2WEB_CONF)" ] && set_option password " = " "$RPC_PASSWD" $A2WEB_CONF
		    else
			# create a2web.conf with options from aria2.conf
			cat ${A2WEB%%/cgi-bin*}/a2web.conf.sample | sed "5,6s/^# //;6s/a2web/\/&/;$ s/$/\nuser = $RPC_USER\npassword = $RPC_PASSWD/" > $A2WEB_CONF
			set_option server " = " "http://localhost:$RPC_PORT/rpc" $A2WEB_CONF
		    fi
		    # read options from a2web.conf
		    RPC_URI=`get_option server $A2WEB_CONF`
		    RPC_PORT=`parse_uri port "$RPC_URI"`
		    RPC_USER=`get_option user $A2WEB_CONF`
		    RPC_PASSWD="$(get_option password $A2WEB_CONF)"
		    # set rpc auth options if specified
		    if [ "$RPC_USER" ]; then
			A2OPTS=" --rpc-user=$RPC_USER"
			[ "$RPC_PASSWD" ] && A2OPTS="$A2OPTS --rpc-passwd=$RPC_PASSWD"
		    fi
		    # set logs
		    LOG=/var/log/$THIS
		    DATE=`date +%Y%m%d%H%M%S`
		    A2LOG=$LOG/aria2.$DATE.log
		    HTLOG=$LOG/httpd.$DATE.log
		    mkdir -p $LOG
		    # start aria2
		    su $USER -c "aria2c --enable-rpc --rpc-listen-port=$RPC_PORT$A2OPTS --log-level=notice --log=-" 2>&1 1>>$A2LOG &
		    # write aria2.pid
		    sleep 2 && mkdir -p $RUN && pgrep -n aria2c > $A2PID
		    # get error if aria2 not running
		    if [ -s $A2PID ]; then
			# set http port options
			HTPORT=" -p $HTTP_PORT" && HTTP_PORT=":$HTTP_PORT"
			# set http auth options if specified
			if [ "$HTTP_USER" ]; then
			    HTTP_AUTH=" --http-user=$HTTP_USER"
			    [ "$HTTP_PASSWD" ] && HTTP_AUTH="$HTTP_AUTH --http-passwd=$HTTP_PASSWD"
			fi
			# check for running a2web.cgi
			aria2c --dry-run$HTTP_AUTH http://localhost$HTTP_PORT$HTTP_PATH &>/dev/null
			if [ $? -ne 0 ]; then
			    # find busybox httpd if running a2web.cgi not found
			    for item in `find ${PATH//:/ } /usr -name httpd -type l`; do
				[ -x $item ] && readlink $item | grep -q busybox && HTBIN=$item && break
			    done
			    # get error if busybox http not found
			    if [ "$HTBIN" ]; then
				# set http auth if specified
				if [ "$HTTP_USER" ]; then
				    # create httpd.conf if not exist
				    [ -f $HTTPD_CONF ] || echo "# httpd.conf" > $HTTPD_CONF
				    # add/replace auth option in httpd.conf
				    grep -q $HTTP_PATH $HTTPD_CONF && sed -i "/a2web\.cgi/c\\$HTTP_PATH:$HTTP_USER:$($HTBIN -m "$HTTP_PASSWD")" $HTTPD_CONF || echo "$HTTP_PATH:$HTTP_USER:$($HTBIN -m "$HTTP_PASSWD")" >> $HTTPD_CONF
				    # set config file option
				    HTCONF=" -c $HTTPD_CONF"
				fi
				# start busybox httpd
				HTCMD="$HTBIN -f -v$HTCONF$HTPORT -h ${A2WEB_PATH%$HTTP_PATH} -u nobody:$(id -gn nobody)"
				cd `mktemp -dt` && script -aqc "$HTCMD" 2>&1 1>>$HTLOG &
				# write httpd.pid
				cd - &>/dev/null && sleep 2 && HTPID=$RUN/httpd.pid && pgrep -fn "$HTCMD" > $HTPID
				# get error if httpd not running
				if [ -s $HTPID ]; then
				    # make starter link to a2webd
				    ln -sf $(cd ${0%/*} && pwd)/$THIS $PREFIX/bin/a2web
				else
				    ERROR="busybox httpd could not start, see $HTLOG"
				    # stop aria2 if httpd could not start
				    kill `cat $A2PID` && rm -rf $RUN
				fi
			    else
				ERROR="running a2web.cgi and installed busybox httpd not found"
			    fi
			fi
		    else
			ERROR="aria2 could not start, see $A2LOG" && rm -rf $RUN
		    fi
		fi
	    fi
	else
	    ERROR="invalid path $A2WEB"
	fi
    fi
    # output message
    if [ "$ERROR" ]; then
	echo "Starting a2web failed ($ERROR)" && return 1
    else
	echo "a2web started successfully" && return 0
    fi
}
# status
status() {
    if [ -d $RUN ]; then
	if [ -f $A2PID ]; then
	    for item in `ls $RUN`; do
		pid=`cat $RUN/$item` && ps | grep -q $pid || ERROR="process ${item##*/} $pid not found"
	    done
	else
	    ERROR="aria2 is not running"
	fi
	if [ "$ERROR" ]; then
	    echo "a2web has error ($ERROR)" && return 1
	else
	    echo "a2web is running" && return 0
	fi
    else
	echo "a2web is not running" && return 1
    fi
}
# reload
reload() {
    # get error if a2webd is not running
    if [ -d $RUN ]; then
	# reload running processes
	for item in `ls $RUN`; do
	    pid=`cat $RUN/$item` && kill -STOP $pid &>/dev/null && sleep 2 && kill -CONT $pid &>/dev/null && continue
	    ERROR="process $pid cannot be reloaded"
	done
	# output message
	if [ "$ERROR" ]; then
	    echo "Reloading a2web failed ($ERROR)" && return 1
	else
	    echo "a2web reloaded successfully" && return 0
	fi
    else
	echo "a2web is not running" && return 1
    fi
}
# stop
stop() {
    # get error if a2webd is not running
    if [ -d $RUN ]; then
	# kill running processes
	for item in `ls $RUN`; do
	    pid=`cat $RUN/$item` && kill $pid &>/dev/null || ERROR="(process ${item##*/} $pid not found)"
	    rm -f $item
	done
	# output message
	rm -rf $RUN && echo "a2web stopped successfully $ERROR" && return 0
    else
	echo "a2web is not running" && return 1
    fi
}
# restart
restart() {
    stop && sleep 2 && start && echo "a2web restarted successfully" && return 0
    echo "Restarting a2web failed" && return 1
}
case $1 in
    start) start ;;
    status) status ;;
    reload) reload ;;
    restart) restart ;;
    stop) stop ;;
    *) help daemon ;;
esac
